//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#ifndef _PLAYER_EVALUATOR_H
#define _PLAYER_EVALUATOR_H
//
#include <global.h>
#include <vector>
//
namespace player
{
template<class T> class Evaluator
{
//structures
private:
   struct Point
   {
      T value;
      double time;
   };
//construction and initialization
public:
   Evaluator(unsigned int p_control_point_count)
   :
      control_points(p_control_point_count),
      current_i(control_points.begin())
   {
   }
   Evaluator(const Evaluator<T> &p_other)
   :
      control_points(p_other.control_points),
      current_i(control_points.begin()+(p_other.current_i-p_other.control_points.begin())),
      current_m(p_other.current_m)
   {
   }
   Evaluator<T> &operator=(const Evaluator<T> &p_other)
   {
      if(&p_other!=this)
      {
         control_points=p_other.control_points;
         current_i=control_points.begin()+(p_other.current_i-p_other.control_points.begin());
         current_m=p_other.current_m;
      }
      return *this;
   }
   void set_control_point(unsigned int p_i,const T &p_value,double p_time)
   {
      Q_ASSERT(p_i<control_points.size());
      control_points[p_i].value=p_value;
      control_points[p_i].time=p_time;
   }
//evaluation
public:
#if UPDATE_WITHOUT_REFERENCE
   void start()
   {
      typename std::vector<Point>::const_iterator i0=control_points.begin();
      while((i0!=control_points.end())&&(i0->time<0))
         ++i0;
      current_i=i0;
      while((current_i!=control_points.end())&&(current_i->time<=i0->time))
         ++current_i;
      if((current_i!=control_points.end())&&(current_i!=i0))
      {
         current_m=(current_i->value-i0->value)*(1.0/(current_i->time-i0->time));
      }
   }
   T update(double p_t0)
   {
      if(current_i==control_points.end())
         return control_points.front().value;
      else
      {
         if(p_t0>=current_i->time)
         {
            typename std::vector<Point>::const_iterator prev_i=current_i;
            while(current_i!=control_points.end()&&current_i->time<=p_t0)
               ++current_i;
            if(current_i==control_points.end())
               //return control_points.front().value;
               return prev_i->value;
            else
               current_m=(current_i->value-prev_i->value)*(1.0/(current_i->time-prev_i->time));
         }
         return current_i->value-current_m*(current_i->time-p_t0);
      }
   }
#endif
   void start(T &p_value)
   {
      typename std::vector<Point>::const_iterator i0=control_points.begin();
      while((i0!=control_points.end())&&(i0->time<0))
         ++i0;
      current_i=i0;
      while((current_i!=control_points.end())&&(current_i->time<=i0->time))
         ++current_i;
      if((current_i!=control_points.end())&&(current_i!=i0))
      {
         current_m=(current_i->value-i0->value)*(1.0/(current_i->time-i0->time));
      }
      p_value=control_points.front().value;
   }
   void update(T &p_value,double p_t0)
   {
      if(current_i!=control_points.end())
      {
         if(p_t0>=current_i->time)
         {
            typename std::vector<Point>::const_iterator prev_i=current_i;
            while(current_i!=control_points.end()&&current_i->time<=p_t0)
               ++current_i;
            if(current_i!=control_points.end())
               current_m=(current_i->value-prev_i->value)*(1.0/(current_i->time-prev_i->time));
            else
               return;
         }
         p_value=current_i->value-current_m*(current_i->time-p_t0);
      }
   }
//data
private:
   std::vector<typename Evaluator<T>::Point> control_points;
   typename std::vector<typename Evaluator<T>::Point>::const_iterator current_i;
   T current_m;
};
}
//
#endif
